//////////////////////////////////////////////////////////////////////
////                                                              ////
////  MDIO.v                                                      ////
////                                                              ////
////                                                              ////
////  This file is part of the "Pico E12" project                 ////
////  http://www.picocomputing.com                                ////
////                                                              ////
////                                                              ////
//////////////////////////////////////////////////////////////////////
////                                                              ////
//// Copyright (C) 2006, Picocomputing, Inc.                      ////
//// http://www.picocomputing.com/                                ////
////                                                              ////
//// This source file may be used and distributed without         ////
//// restriction provided that this copyright statement is not    ////
//// removed from the file and that any derivative work contains  ////
//// the original copyright notice and the associated disclaimer. ////
////                                                              ////
//// This source file is free software; you can redistribute it   ////
//// and/or modify it under the terms of the GNU Lesser General   ////
//// Public License as published by the Free Software Foundation; ////
//// either version 2.1 of the License, or (at your option) any   ////
//// later version.                                               ////
////                                                              ////
//// This source is distributed in the hope that it will be       ////
//// useful, but WITHOUT ANY WARRANTY; without even the implied   ////
//// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR      ////
//// PURPOSE.  See the GNU Lesser General Public License for more ////
//// details.                                                     ////
////                                                              ////
//// You should have received a copy of the GNU Lesser General    ////
//// Public License along with this source; if not, download it   ////
//// from http://www.opencores.org/lgpl.shtml                     ////
////                                                              ////
////////////////////////////////////////////////////////////////////JF

//MDIO Ethernet Management Interface

`include "PicoDefines.v"
`define MDIO_PHY_ADDRESS 5'b00000

//This is a MDIO interface for Ethernet PHYs
//Preamble supression on the PHY must be enabled

module MDIO(CLOCK1, MemRead, MemWrite, MemAddress, DataIn, DataOut, Wait, ETH_25MHZ, ETH_COMA, ETH_RESET, MDIO_IN, MDIO_OUT, MDC, TRIS_MDIO);

input CLOCK1;                                        //50 MHz Clock
input MemRead;                                       //Memory Read
input MemWrite;                                      //Memory Write
input [31:1]MemAddress;                              //Memory Address
input [0:15]DataIn;                                  //Host -> MDIO
output [0:15]DataOut;                                //MDIO -> Host
output Wait;                                         //PCMCIA Extend Cycle Request (This is a slow interface)

output ETH_25MHZ;                                    //25 MHz Ethernet Clock
output ETH_COMA;                                     //Ethernet Powerdown Control
output ETH_RESET;                                    //Ethernet Reset Control

input MDIO_IN;                                       //MDIO Serial Data In to Module
output MDIO_OUT;                                     //MDIO Serial Data Out to Module
output TRIS_MDIO;                                    //MDIO Tristate Control
output MDC;                                          //MDIO Clock

reg TRIS_MDIO;                                       //MDIO Output Tristate Control
reg MDIO_OUT;                                        //MDIO Output
reg MDIO_IN_OLD;                                     //MDIO Old Input (Captured on Negative Edge)
reg [0:15]DataOutBuffer;                             //MDIO Data Out Buffer
reg WaitReg;                                         //PCMCIA Extend Transaction
reg [2:0]ClockDivider;                               //Clock dividers for Slow Clocks
reg [4:0]Sequence;                                   //MDIO Transaction Sequence Number
reg [1:0]HoldOff;                                    //End of Transaction Delay

//synthesis attribute INIT of TRIS_MDIO is 1;
//synthesis attribute INIT of MDIO_OUT is 1;
//synthesis attribute INIT of DataOutBuffer is 0000000000000000;
//synthesis attribute INIT of WaitReg is 0;
//synthesis attribute INIT of ClockDivider is 00000;
//synthesis attribute INIT of Sequence is 00000;
//synthesis attribute INIT of HoldOff is 11;

wire [0:31]OutBuffer;
wire MDIORead = (MemRead) && (MemAddress[31:6] == `MDIO_ADDRESS);
wire MDIOWrite = (MemWrite) && (MemAddress[31:6] == `MDIO_ADDRESS);
wire Transfer = (MDIORead || MDIOWrite);

always @(posedge CLOCK1) 							          //Clock Generation
    ClockDivider = ClockDivider + 1;

assign ETH_25MHZ = ClockDivider[0];                    //25 MHz Clock
assign MDC = ClockDivider[2];                          //6.25 MHz Clock
assign ETH_COMA = 0;                                   //Powersave Disabled
assign ETH_RESET = 1;                                  //Reset Disabled

assign OutBuffer[0:1] = 2'b01;                         //Start Sequence
assign OutBuffer[2:3] = {MemRead,~MemRead};            //Direction
assign OutBuffer[4:8] = `MDIO_PHY_ADDRESS;             //Phy Address
assign OutBuffer[9:13] = MemAddress[5:1];              //Register Address
assign OutBuffer[14:15] = 2'b10;                       //Turnaround
assign OutBuffer[16:31] = DataIn[0:15];                //Data

PulseGen PulseGen(MDC, Transfer, WaitFastRise);

assign Wait = WaitFastRise || WaitReg;

//Start and Stop Control
always @(posedge MDC)                                  //Require host to wait for transfer to be complete
begin
	if (HoldOff[1:0] != 2'b11) begin
		HoldOff[1:0] <= {HoldOff[0],1'b1};
	end
else		  
	if ((Sequence == 0) && (Transfer == 1)) begin
		WaitReg <= 1;
	end
else
   if (Sequence == 31) begin
		WaitReg <= 0;
		HoldOff[1:0] <= 2'b00;
	end
end

//Sequence Counter
always @(posedge MDC) begin               
	if (WaitReg == 1) Sequence <= Sequence + 1;
end

//Host -> MDIO
always @(negedge MDC) begin               
	MDIO_OUT <= OutBuffer[Sequence];
	if (WaitReg == 0) TRIS_MDIO <= 1;
else
	if (|Sequence[4:0] == 0) TRIS_MDIO <= 0;
	if ((Sequence[4:0] == 5'h0E) && (MDIORead == 1)) TRIS_MDIO <= 1;
end

//MDIO -> Host
always @(negedge MDC)
	MDIO_IN_OLD <= MDIO_IN;

always @(posedge MDC)
	if (Sequence[4] == 1'b1) DataOutBuffer[Sequence[3:0]] = MDIO_IN_OLD;

assign DataOut[0:15] = (MDIORead)?DataOutBuffer[0:15] : 16'b0;

endmodule